using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using EnvDTE;
using EnvDTE80;

namespace Microsoft.WowAddonStudio.Lua.RuntimeService.WowBench.Resolvers
{
	/// <summary>
	/// Resolves and translates expression in Lua language.
	/// </summary>
	public sealed class ExpressionResolver : ICommandResolver, IDisposable
	{
		private readonly DTE2 dte;
		private const string MULTILINE_COMMAND_TEMPLATE = "dofile(\"{0}\")";
		private const string FILE_EXTENSION = ".lua";
		private IList<string> tempFiles;

		#region Lifecycle Methods

		/// <summary>
		/// Initializes a new instance of the <see cref="ExpressionResolver"/> class.
		/// </summary>
		/// <param name="provider">The <see cref="IServiceProvider"/> parameter.</param>
		public ExpressionResolver(IServiceProvider provider)
		{
			if (provider == null)
				throw new ArgumentNullException("provider");

			dte = (DTE2) provider.GetService(typeof (DTE));
		}

		#endregion

		#region ICommandResolver Members

		/// <summary>
		/// Resolves the given expression into WoWBench format.
		/// </summary>
		/// <param name="expression">The expression.</param>
		/// <returns></returns>
		public string Resolve(string expression)
		{
			if (string.IsNullOrEmpty(expression))
				throw new ArgumentNullException("expression");

			if (IsMultiline(expression))
			{
				object activeSolutionProjects = dte.ActiveSolutionProjects;
				if (dte.Solution != null && activeSolutionProjects != null)
				{
					//Get and convert all active projects
					object[] objects = (object[]) activeSolutionProjects;
					Project[] projects = Array.ConvertAll(
						objects, project => (Project) project);

					if (projects.Length > 0)
					{
						//Get the full path of project
						var path = (string) projects[0].Properties.Item("FullPath").Value;
						path = Path.GetDirectoryName(path);

						//Create temporary file for multiline text to hold expressions
						string tempFileName = AddTemporaryLuaFile(expression, Path.Combine(path, "Debug"));

						//Create WoWBench command to load expression file into emulator context
						expression = PrepareLuaCommand(String.Format(MULTILINE_COMMAND_TEMPLATE, tempFileName));
					}
				}
			}
			return expression;
		}

		/// <summary>
		/// Reset the current state of Resolver.
		/// </summary>
		public void Reset()
		{
			if (tempFiles != null)
			{
				foreach (string tempFile in tempFiles)
				{
					if (File.Exists(tempFile))
					{
						try
						{
							File.Delete(tempFile);
						}
						catch (Exception e)
						{
							Trace.WriteLine(e);
						}
					}
				}
				tempFiles.Clear();
			}
		}

		#endregion

		#region Private Function Members

		/// <summary>
		/// Adds the temporary lua file.
		/// </summary>
		/// <param name="expression">The expression.</param>
		/// <param name="path">The path.</param>
		/// <returns></returns>
		private string AddTemporaryLuaFile(string expression, string path)
		{
			try
			{
				if (path == null)
					throw new ArgumentNullException("path");

				if (tempFiles == null)
					tempFiles = new List<string>();

				if (!Directory.Exists(path))
					Directory.CreateDirectory(path);

				string fileName = Path.Combine(path, String.Concat(Guid.NewGuid(), FILE_EXTENSION));

				using (var stream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
				{
					using (var writer = new StreamWriter(stream))
					{
						writer.Write(expression);
					}
				}

				tempFiles.Add(fileName);

				return fileName;
			}
			catch (Exception ex)
			{
				Trace.WriteLine(ex);
			}

			return String.Empty;
		}

		/// <summary>
		/// Indicates that the given expression is multi-line.
		/// WoWBench does not process multiline expression in command line mode.
		/// </summary>
		/// <param name="expression">The expression.</param>
		/// <returns></returns>
		private static bool IsMultiline(string expression)
		{
			return expression.Contains("\n");
		}

		/// <summary>
		/// Formats lua command for WoWBench processing.
		/// </summary>
		/// <param name="expression">The expression.</param>
		/// <returns></returns>
		private static string PrepareLuaCommand(string expression)
		{
			return expression.Replace("\\", "/");
		}

		#endregion

		#region IDisposable Members


		/// <summary>
		/// Performs application-defined tasks associated with freeing,
		/// releasing, or resetting unmanaged resources.
		/// </summary>
		public void Dispose()
		{
			Reset();
		}

		#endregion
	}
}